package cut_stock_2;

import Jama.Matrix;

public class CutStock {
    public static void main(String[] args) {
        DataReader reader = new DataReader();
        reader.loadFile("src/cut_stock_2/cutstock2.dat");

        Solver solver = new Solver(reader.stockLength, reader.specs, reader.requirements);
        solver.solve();
    }
}

class Solver {

    public final int stockLength;
    public final Matrix specs;
    public final Matrix requirements;
    public final int specNum;

    private boolean isOptimal = false;

    private Matrix A; // 系数矩阵，随着列生成的过程不断增加

    Solver(int stockLength, double[] specs, double[] requirements) {
        this.stockLength = stockLength;
        this.specNum = specs.length;
        this.specs = new Matrix(specs, this.specNum);
        this.requirements = new Matrix(requirements, this.specNum);
    }

    public void solve() {
        this.A = getInitSolution();

        // 根据初始的A求解主问题
        MainProblem mp = new MainProblem(this.A, this.requirements);
        mp.solve();

        while (!isOptimal) {
            // 求解子问题
            SubProblem sp = new SubProblem(mp.shadowPrice, this.stockLength, this.specs);
            sp.solve();

            // 新增列
            int xNum = A.getColumnDimension();
            Matrix temp = new Matrix(specNum, xNum + 1, 0);
            temp.setMatrix(0, specNum - 1, 0, xNum - 1, A);
            temp.setMatrix(0, specNum - 1, xNum, xNum, sp.solutions);
            A = temp.copy();

            // 再求解主问题
            mp = new MainProblem(this.A, this.requirements);
            mp.solve();

            // 更新isOptimal
            if (sp.objVal <= 0) {
                isOptimal = true;
            }
        }

        // 输出最优解（不取整）
        specs.transpose().print(specNum, 0);
        for (int i = 0; i < mp.solutions.getRowDimension(); i++) {
            if (mp.solutions.get(i, 0) != 0) {
                System.out.println("方案" + i + "：" + mp.solutions.get(i, 0) + "根");
                A.getMatrix(0, specNum - 1, i, i).transpose().print(specNum, 0);
            }
        }
    }

    private Matrix getInitSolution() {
        Matrix A = new Matrix(specNum, specNum, 0);
        for (int i = 0; i < specNum; i++) {
            A.set(i, i, (int) (stockLength / specs.get(i, 0)));
        }
        return A;
    }

}
